資列頁(16kb大小)的結構有7個部分
1.使用者紀錄(user records)
2.空閒空間(free space)
3.頁面中最小與最大的紀錄(infimum+supermum)
4.頁面目錄(page directory)
5.頁面表頭(page header)
6.檔案表頭(file header)
7.檔案結尾(file trailer)
前文提到前三個的部分,今天會當作大家已經熟悉前面的內容,繼續說明剩下的部分,在過程中如有不清楚的地方就再回去複習吧。
根據之前的學習我們已經知道資料頁的結構是一個按照主鍵大小排序的單向鏈結串列。
此時我們想要查詢資料的話,最直觀且最差的做法就是一筆一筆依序查詢,當資料頁有n筆我們新增的紀錄,那就查詢n次吧...
大家應該都認同這不是一個好的解法,我們來學習Innodb的工程師是怎麼設計的
設計的思維就像是我們在看一本書時,最前面會有各章節的頁碼,透過其我們可以知道要查詢的內容從那一頁開始找比較快。
Innodb的工程師就是這樣針對所有紀錄去分組(就像書的各章節)並定義各組的槽(就像章節的頁碼)。
具體的作法細節如下:
分組有一個規定,infimum紀錄所在的組只有它自己一筆紀錄,supermum紀錄所在的組包含它自己只能有1到8筆紀錄,其餘的組別則為4到8筆紀錄。
這邊進一步補充說明前面第一點分組的細節
舉一個例子來說明:
現有16筆紀錄
mysql> insert into ryan_demo2_table(c1,c2,c3) values (1,100,'a'),(2,200,'b'),(3,300,'c'),(4,400,'d'),(5,500,'e'),(6,600,'f'),(7,700,'g'),(8,800,'h'),(9,900,'i'),(10,1000,'j'),(11,1100,'k'),(12,1200,'l'),(13,1300,'m'),(14,1400,'n'),(15,1500,'o'),(16,1600,'p');
Query OK, 16 rows affected (0.01 sec)
Records: 16 Duplicates: 0 Warnings: 0
mysql> select * from ryan_demo2_table;
+------+------+------+
| c1 | c2 | c3 |
+------+------+------+
| 1 | 100 | a |
| 2 | 200 | b |
| 3 | 300 | c |
| 4 | 400 | d |
| 5 | 500 | e |
| 6 | 600 | f |
| 7 | 700 | g |
| 8 | 800 | h |
| 9 | 900 | i |
| 10 | 1000 | j |
| 11 | 1100 | k |
| 12 | 1200 | l |
| 13 | 1300 | m |
| 14 | 1400 | n |
| 15 | 1500 | o |
| 16 | 1600 | p |
+------+------+------+
16 rows in set (0.01 sec)
其實在資料頁裡面有18筆紀錄(包含自動建立的infimum跟supermum紀錄)
而這裡的分組會是(以c1欄位主鍵值來看)
infimum紀錄自己1組(槽0 對應的主鍵值為infimum)
1、2、3、4四筆1組(槽1 對應的主鍵值為4)
5、6、7、8四筆1組(槽2 對應的主鍵值為8)
9、10、11、12四筆1組(槽3 對應的主鍵值為12)
13、14、15、16四筆紀錄跟supermum紀錄1組(槽4 對應的主鍵值為supermum)
總共5組
在這樣的情境下,我們想搜尋一筆主鍵值為6的紀錄,搜尋的過程會是以下這樣的。
1.一開始low為0,high為4,計算中間槽的位置(0+4)/2=2,查看槽2對應的主鍵值為8,因爲6小於8,所以high變為2(界限縮小),而low不變一樣為0
2.重新計算中間槽的位置(0+2)/2=1,查看槽1對應的主鍵值為4,因為6大於4,所以low為1(界限縮小),而high不變一樣為2
3.因為high-low為1,表示要搜尋的紀錄就在槽2的組別裡面,這時只要找到槽2主鍵值最小的那一筆紀錄,沿著單向鏈結串列歷遍槽2的所有紀錄即可找到我們要的紀錄
本來要比對16次的紀錄變成只要歷遍5,6就找到6了,就算不幸為此組最後一筆,1組紀錄筆數最多為8筆,因此最多也就8次,大大的提升了搜尋的速度。
Innodb為了想得到資料頁的紀錄狀態定義了頁面標頭,方便知道情況。
這邊總共有14個狀態(佔用固定56位元組)但我不會全部列出來,我覺得現在看也看不懂的就不贅述了,等未來有遇到再來補充大家也比較清楚。我這邊就特別提幾個應該要知道且實用的狀態。
前面的頁面表頭是紀錄資料頁的各種狀態,而檔案表頭則不侷限於資料頁,包含了其他各種類型頁面的紀錄狀態。這裡一樣只說明幾個比較重要的狀態。
我們知道Innodb會先把資料從磁碟讀取到記憶體去更新(因為磁碟速度太慢),更新完畢後在刷新回磁碟。
但如果在記憶體更新後,發生意外(斷電等),導致沒有刷新回磁碟,兩邊資料不一致的bug就尷尬了。
所以Innodb在每個頁的尾部增加了檔案結尾的部分。佔8位元組包含兩個部分(校正碼4位元組及最後被修改時對應的LSN的後4位元組[LSN是新名詞之後會再說明,先大概知道有這東西就好])。
透過比對檔案表頭與檔案結尾的校正碼及LSN驗證來確保資料成功刷新。
今天的內容較多,但這些都是基礎且很重要的東西,大家要好好熟悉,因為這對接下來要說明的內容都是必要的前提知識。在一起好好加油吧~耶~吃蒼蠅去!